/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.opentoast.maven;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.eclipse.WorkspaceConfiguration;
import org.apache.maven.plugin.eclipse.reader.ReadWorkspaceLocations;
import org.apache.maven.plugin.ide.IdeDependency;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;

/**
 * Super class for all S2DM Maven Plugin Mojo classes.
 * 
 * @author <a href="mailto:jiwhiz@gmail.com">Yuan Ji</a>
 * 
 */
public abstract class AbstractS2DMMojo extends AbstractMojo implements LogEnabled
{
    protected static final String MAVEN_PACKAGING_POM = "pom";
    protected static final String MAVEN_PACKAGING_PAR = "dm-par";
    
    /**
     * The project whose project files to create.
     * 
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    protected MavenProject project;

    /**
     * The currently executed project (can be a reactor project).
     * 
     * @parameter expression="${executedProject}"
     * @readonly
     */
    protected MavenProject executedProject;

    /**
     * If the executed project is a reactor project, this will contains the full list of projects in the reactor.
     * 
     * @parameter expression="${reactorProjects}"
     * @required
     * @readonly
     */
    protected List<MavenProject> reactorProjects;

    /**
     * The project packaging.
     * 
     * @parameter expression="${project.packaging}"
     */
    protected String packaging;

    /**
     * Local maven repository.
     * 
     * @parameter expression="${localRepository}"
     * @required
     * @readonly
     */
    protected ArtifactRepository localRepository;

    /**
     * Plexus logger needed for debugging manual artifact resolution.
     */
    protected Logger logger;

    /**
     * Eclipse workspace directory.
     * 
     * @parameter expression="${eclipse.projectDir}" alias="outputDir"
     */
    protected File eclipseProjectDir;

    /**
     * The default output directory
     * 
     * @parameter expression="${outputDirectory}" alias="outputDirectory"
     *            default-value="${project.build.outputDirectory}"
     * @required
     */
    protected File buildOutputDirectory;

    /**
     * This eclipse workspace is read and all artifacts detected there will be
     * connected as eclipse projects and will not be linked to the jars in the
     * local repository. Requirement is that it was created with the similar wtp
     * settings as the reactor projects, but the project name template my
     * differ. The pom's in the workspace projects may not contain variables in
     * the artefactId, groupId and version tags.
     * 
     * @since 2.5
     * @parameter expression="${eclipse.workspace}"
     */
    protected String workspace;

    /**
     * Getter for <code>project</code>.
     * 
     * @return Returns the project.
     */
    public MavenProject getProject()
    {
        return project;
    }

    /**
     * Setter for <code>project</code>.
     * 
     * @param project The project to set.
     */
    public void setProject( MavenProject project )
    {
        this.project = project;
    }

    /**
     * Getter for <code>executedProject</code>.
     * 
     * @return Returns the executedProject.
     */
    public MavenProject getExecutedProject()
    {
        return executedProject;
    }

    /**
     * Setter for <code>executedProject</code>.
     * 
     * @param executedProject The executedProject to set.
     */
    public void setExecutedProject( MavenProject executedProject )
    {
        this.executedProject = executedProject;
    }

    /**
     * Getter for <code>localRepository</code>.
     * 
     * @return Returns the localRepository.
     */
    public ArtifactRepository getLocalRepository()
    {
        return localRepository;
    }

    /**
     * Setter for <code>localRepository</code>.
     * 
     * @param localRepository The localRepository to set.
     */
    public void setLocalRepository( ArtifactRepository localRepository )
    {
        this.localRepository = localRepository;
    }

    public File getEclipseProjectDir()
    {
        return eclipseProjectDir;
    }

    public void setEclipseProjectDir(File eclipseProjectDir)
    {
        this.eclipseProjectDir = eclipseProjectDir;
    }

    public String getWorkspace()
    {
        return workspace;
    }

    public void setWorkspace(String workspace)
    {
        this.workspace = workspace;
    }

    /**
     * @see org.codehaus.plexus.logging.LogEnabled#enableLogging(org.codehaus.plexus.logging.Logger)
     */
    public void enableLogging( Logger logger )
    {
        this.logger = logger;
    }

    public WorkspaceConfiguration getWorkspaceConfiguration()
    {
      	WorkspaceConfiguration workspaceConfiguration = new WorkspaceConfiguration();
        if (workspace != null)
        {
            workspaceConfiguration.setWorkspaceDirectory(new File(workspace));
        }
        new ReadWorkspaceLocations().init(getLog(), workspaceConfiguration, project, null);
        return workspaceConfiguration;
    }

    /**
     * Use packaging type to figure out whether it is a s2dm par project.
     * @return
     */
    protected boolean isS2DMParProject(){
        return MAVEN_PACKAGING_PAR.equals(packaging);
    }
    

    @SuppressWarnings("unchecked")
    protected IdeDependency[] doDependencyResolution(){
        List<Dependency> deps = (List<Dependency>)getProject().getDependencies();
        List dependencies = new ArrayList();
        
        for (Dependency dependency : deps){
            IdeDependency dep = new IdeDependency(
                    dependency.getGroupId(),
                    dependency.getArtifactId(),
                    dependency.getVersion(),
                    dependency.getClassifier(),
                    isAvailableAsAReactorProject( dependency ),
                    Artifact.SCOPE_TEST.equals( dependency.getScope() ),
                    Artifact.SCOPE_SYSTEM.equals( dependency.getScope() ),
                    Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ),
                    Artifact.SCOPE_TEST.equals( dependency.getScope() ), //we add test scope dependencies to classpath
                    null,
                    dependency.getType(),
                    true,
                    null,
                    0,
                    dependency.getArtifactId()  //use artifactId as project name
            );
            dependencies.add( dep );
        }
        
        return (IdeDependency[]) dependencies.toArray( new IdeDependency[dependencies.size()] );
    }

    /**
     * Utility method that locates a project producing the given artifact.
     * 
     * @param artifact the artifact a project should produce.
     * @return <code>true</code> if the artifact is produced by a reactor projectart.
     */
    protected boolean isAvailableAsAReactorProject( Dependency dependency )
    {
        if ( reactorProjects != null )
        {
            for (MavenProject reactorProject : reactorProjects)
            {
                if ( reactorProject.getGroupId().equals( dependency.getGroupId() ) &&
                    reactorProject.getArtifactId().equals( dependency.getArtifactId() ) )
                {
                    if ( reactorProject.getVersion().equals( dependency.getVersion() ) )
                    {
                        return true;
                    }
                    else
                    {
                        getLog().info( "Depedency " +
                                dependency.getGroupId() + ":" + dependency.getArtifactId() +
                                " already available as a reactor project, but with different version. Expected: " +
                                dependency.getVersion() + ", found: " + reactorProject.getVersion() );
                    }
                }
            }
        }
        return false;
    }

}
